package model.AI;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.ImageIcon;

import control.networking.RiskAIClient;

import model.Continent;
import model.Map;
import model.Player;
import model.Territory;
import model.TradeCard;
import model.Map.GamePhase;

/**
 * The Expert implementation of the Cyborg interface.
 * 
 * @author David Shefchik
 * 
 */
public class ExpertCyborg extends Player implements Cyborg {
	List<Territory> myTerritories;
	List<Continent> myContinents;

	private ImageIcon pic;
	private String name;
	private int age;
	private String location;
	private int rand;
	Player playerTarget;
	Continent contTarget;
	private boolean gameHasStarted;
	private boolean attacking;
	private int attackCount;
	private Role role;
	private RiskAIClient client;

	// public ExpertCyborg(String name, Color color, ImageIcon icon, Map map)
	public ExpertCyborg(String name, Color color, ImageIcon icon) {
		super(name, color, icon);
		this.setDiceAttack(3);
		this.setDiceDefend(2);
		name = "HAL";
		age = 5;
		location = "Space";
		gameHasStarted = false;
		rand = (int) (Math.random() * 3);
		if (rand == 0)
			role = Role.CONQUEROR;
		else if (rand == 1)
			role = Role.DEFENDER;
		else
			role = Role.SCAVENGER;

	}

	public void cardPhase() {
		this.updateTerritories();
		if (this.getNumCards() >= 3) {
			if (this.getNumCards() == 5) {// Checks if he has 5 cards
				this.attemptTrade();// trades
				this.notifyObservers("NewMap");
				try {
					synchronized (this) {
						this.wait(1000);
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				List<Integer> numCards = MapInfo
						.getOtherPlayersCardNumbers(this);
				if (MapInfo.getWeakestPlayer(this).getNumCards() == 5
						&& MapInfo.getWeakestPlayer(this).getNumArmies() < this
								.getNumArmies()) {
					if (this.getNumArmies() > (MapInfo.getWeakestPlayer(this)
							.getNumArmies() * 2)) {
						this.attemptTrade();
						this.notifyObservers("NewMap");
						;
					}
					try {
						synchronized (this) {
							this.wait(1000);
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					if (this.rand < 3) {
						this.attemptTrade();

						this.notifyObservers("NewMap");
					}
					try {
						synchronized (this) {
							this.wait(1000);
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

			}
		}

	}

	public void placePhase() {
		this.updateTerritories();

		while (this.troopsToAdd > 0) {

			if (MapInfo.ownsAContinent(this)) {
				contTarget = myContinents.get(0);
				List<Territory> contBorders = MapInfo
						.getContinentBorders(contTarget);
				while (this.troopsToAdd > 0) {
					for (Territory temp : myTerritories) {

						if (MapInfo.territoryIsClustered(temp, (Player) this)
								&& MapInfo.hasBorderingEnemyTerritories(this,
										temp)) {
							temp.addTroop(1);
							this.removeBonus(1);
							setChanged();
							this.notifyObservers("NewMap");
							try {
								synchronized (this) {
									this.wait(500);
								}
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							break;
							// this.wait(500);

						}
					}

				}

			} else {
				contTarget = MapInfo.getEasiestContinent(this);
				if (this.troopsToAdd > 0) {
					for (Territory terr : contTarget.listTerritory()) {
						if (terr.getRuler().equals(this)) {
							terr.addTroop(1);
							this.removeBonus(1);
							setChanged();
							this.notifyObservers("NewMap");
							try {
								synchronized (this) {
									this.wait(500);
								}
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							break;
						}
					}
				}

			}
			if (troopsToAdd > 0) {
				Collections.shuffle(myTerritories);
				Territory toAddTo = myTerritories.get(0);
				if (contTarget == null) {
					contTarget = MapInfo.getEasiestContinent(this);

				} else {
					for (Territory terr : myTerritories) {
						if (terr.getContinent().equals(contTarget)) {
							if (terr.getTroopNumber() == 1) {
								toAddTo = terr;
//								setChanged();		never mind
//								notifyObservers("NewMap");
								break;
							} else {
								toAddTo = terr;
							}

						}
					}

				}

				System.out.println("terr: " + toAddTo.getTerritoryName() );


				toAddTo.addTroop(1);
				this.removeBonus(1);

				setChanged();
				this.notifyObservers("NewMap");;

				try {
					synchronized (this) {
						this.wait(500);
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}

	public void attackPhase() {
		this.updateTerritories();

		attacking = true;
		attackCount = 0;
		Territory target;
		Territory origin;
		if (role == Role.DEFENDER) {
			if (MapInfo.ownsAContinent(this)) {

				List<Territory> list = MapInfo.getContinentBorders(contTarget);
				target = MapInfo.getWeakestBorderingEnemyTerritory(list.get(0));
				for (Territory temp : list) {
					Territory tempTarget = MapInfo
							.getWeakestBorderingEnemyTerritory(temp);
					if (tempTarget.getTroopNumber() == 1
							&& temp.getTroopNumber() > 4) {
						this.attack(temp, tempTarget);
						attacking = false;
						break;

					} else {
						if (contTarget == null) {
							contTarget = MapInfo.getEasiestContinent(this);
						} else {
							for (Territory terr : myTerritories) {
								if (terr.getContinent().equals(contTarget)) {
									for (Territory neighbor : terr
											.listNeighbors()) {
										if (neighbor.getContinent().equals(
												contTarget)
												&& terr.getTroopNumber() > neighbor
														.getTroopNumber()) {
											attack(terr, neighbor);
											attacking = false;
											break;
										}
									}
								}

							}
							if (attacking == true) {
								Collections.shuffle(myTerritories);
								for (Territory terr : myTerritories.get(0)
										.listNeighbors()) {
									if (!terr.getRuler().equals(this)
											&& terr.getTroopNumber() < myTerritories
													.get(0).getTroopNumber()) {

										attack(myTerritories.get(0), terr);
										attacking = false;
									}
								}

							}
						}

					}

				}

			}

		}

		else if (role == Role.CONQUEROR) {
			contTarget = MapInfo.getEasiestContinent(this);
			if (MapInfo.ownsAContinent(this)) {
				for (Territory temp : myTerritories) {
					List<Territory> neighbors = temp.listNeighbors();
					for (Territory target1 : neighbors) {
						if (target1.getContinent().equals(contTarget)) {

							this.attack(temp, target1);
						}
					}
				}

			} else {
				if (MapInfo.getPlayersLargestTerritory(this).getContinent()
						.equals(contTarget)) {

				}
				for (int i = 0; i < myTerritories.size(); i++) {
					this.updateTerritories();
					if (!MapInfo.getEnemyBorderingTerritories(
							myTerritories.get(i)).isEmpty())
						if (myTerritories.get(i).getTroopNumber() > (MapInfo
								.getWeakestBorderingEnemyTerritory(
										myTerritories.get(i)).getTroopNumber() / 2)) {

							attack(
									myTerritories.get(i),
									MapInfo
											.getWeakestBorderingEnemyTerritory(myTerritories
													.get(i)));
							attacking = false;
							break;

						}

				}

			}

		} else {
			playerTarget = MapInfo.getWeakestPlayer(this);
			for (int i = 0; i < myTerritories.size(); i++) {
				this.updateTerritories();
				if (!MapInfo.getEnemyBorderingTerritories(myTerritories.get(i))
						.isEmpty())
					if (myTerritories.get(i).getTroopNumber() > (MapInfo
							.getWeakestBorderingEnemyTerritory(
									myTerritories.get(i)).getTroopNumber() / 2)) {

						attack(
								myTerritories.get(i),
								MapInfo
										.getWeakestBorderingEnemyTerritory(myTerritories
												.get(i)));
						attacking = false;
						break;

					}

			}

		}

		if (this.isCardEligible() && !this.getMap().getMapCards().isEmpty()) {
			this.getMap().giveCard(this);
			setChanged();
			this.setCardEligible(false);

		}
	}

	public void movePhase() {
		boolean moved = false;
		this.updateTerritories();
		for (Territory temp : myTerritories) {
			if (temp.getTroopNumber() > 1
					&& !MapInfo.hasBorderingEnemyTerritories(this, temp)) {
				for (Territory dest : temp.listNeighbors()) {
					if (MapInfo.hasBorderingEnemyTerritories(this, dest)) {
						if (!moved) {
							new model.Movement(temp, dest, temp
									.getTroopNumber() - 1);
							setChanged();
							this.notifyObservers("NewMap");
							;
							try {
								synchronized (this) {
									this.wait(500);
								}
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							moved = true;
						}
					}
				}
			}
		}

	}

	public void talkTrash() {

	}

	private enum Role {
		DEFENDER, SCAVENGER, CONQUEROR;
	}

	private void attack(Territory origin, Territory target) {
		while ((!target.getRuler().equals(this))
				&& target.getTroopNumber() < origin.getTroopNumber()) {
			new model.Combat(origin, target);
			setChanged();
			this.notifyObservers("NewMap");
			try {
				synchronized (this) {
					this.wait(500);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	public void run() {
		System.out.println("\n" + this.getName() + "'s TURN ");
		if (this.getMap().getPhase() == GamePhase.PLAYING) {
			System.out.println("Cards: " + this.getNumCards() + " \nRole: "
					+ this.role);
			gameHasStarted = true;
			MapInfo.calculateTurnBonus(this);
			System.out.println("Bonus: " + this.getBonus());
			System.out.println("TroopsToAdd: " + this.troopsToAdd);
			cardPhase();
			placePhase();
			attackPhase();
			movePhase();
			talkTrash();
		} else if (this.getMap().getPhase() == GamePhase.SELECTING) {
			this.troopsToAdd = 1;
			selectTerritories();
			if (MapInfo.listUnownedTerritories(this).isEmpty()) {
				this.getMap().setPhase(GamePhase.PLACING);
				setChanged();
				this.notifyObservers("NewMap");
			}
		} else {
			this.troopsToAdd = 1;
			System.out.println(this+" placing troops");
			placePhase();

			if (this.getBonus() == 0) {
				this.getMap().setPhase(GamePhase.PLAYING);
				setChanged();
				this.notifyObservers("NewMap");
			}
		}

		setChanged();
		this.notifyObservers("EndTurn");
	}

	private void selectTerritories() {
		Territory toAddTo;
		List<Territory> list = MapInfo.listUnownedTerritories(this);
		Collections.shuffle(list);
		toAddTo = list.get(0);
		for (Territory temp : list) {
			if (MapInfo.territoryIsClustered(temp, (Player) this)) {
				toAddTo = temp;
			}
		}

		toAddTo.addTroop(1);
		toAddTo.setRuler(this);
		this.removeBonus(this.troopsToAdd);
		setChanged();
		this.notifyObservers("NewMap");
	}

	private void attemptTrade() {
		List<model.TradeCard.Choice> tradeList = TradeCard.tradeList(this);
		if (!tradeList.isEmpty()) {

			model.Card card1 = tradeList.get(0).getCard1();
			model.Card card2 = tradeList.get(0).getCard2();
			model.Card card3 = tradeList.get(0).getCard3();
			TradeCard.tradeCard(this, card1, card2, card3);
			setChanged();
			this.notifyObservers("NewMap");
		}
	}

	private void updateTerritories() {
		myTerritories = MapInfo.getPlayersTerritories(this);
		myContinents = MapInfo.listPlayersContinents(this);

	}

}
